package com.wdciti.sccp.iot.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wdciti.sccp.iot.gateway.domain.Point2D;

import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.List;

/**
 * @author tonghui
 * @date 2023-08-26
 */
public class PolygonOutlineUtil {

    private static double EARTH_RADIUS = 6378137;

    //+
    public static Point2D plus(Point2D left, Point2D right) {
        return new Point2D(left.x + right.x, left.y + right.y);
    }

    //-
    public static Point2D reduce(Point2D left, Point2D right) {
        return new Point2D(left.x - right.x, left.y - right.y);
    }

    //value*
    public static Double rideDouble(Point2D left, Point2D right) {
        return left.x * right.x + left.y * right.y;
    }

    //*
    public static Point2D ride(Point2D left, Double value) {
        return new Point2D(left.x * value, left.y * value);
    }

    // 自定义的向量差乘运算符号 **
    public static Double operator(Point2D left, Point2D right) {
        return left.x * right.y - left.y * right.x;
    }

    // 初始化顶点队列
    public static List<Point2D> initPList(String str) {
        List<Point2D> pList = new ArrayList<>();
        String[] split = str.split(";");
        for (String point : split) {
            String[] split1 = point.split(",");
            pList.add(new Point2D(Double.valueOf(split1[0]), Double.valueOf(split1[1])));
        }
        return pList;
    }

    // 初始化dpList  两顶点间向量差
    public static List<Point2D> initDPList(List<Point2D> pList) {
        List<Point2D> dpList = new ArrayList<>();
        System.out.println("计算两顶点间向量差:dpList");
        for (int index = 0; index < pList.size(); index++) {
            int i = index == pList.size() - 1 ? 0 : index + 1;
            dpList.add(reduce(pList.get(index == pList.size() - 1 ? 0 : index + 1), pList.get(index)));
        }
        return dpList;
    }

    // 初始化ndpList，单位化两顶点向量差
    public static List<Point2D> initNDPList(List<Point2D> dpList) {
        List<Point2D> ndpList = new ArrayList<>();
        System.out.println("开始计算单位化两顶点向量差:ndpList");
        for (int index = 0; index < dpList.size(); index++) {
            ndpList.add(ride(dpList.get(index), (1.0 / Math.sqrt(rideDouble(dpList.get(index), dpList.get(index))))));
        }
        return ndpList;
    }

    // 计算新顶点， 注意参数为负是向内收缩， 为正是向外扩张
    private static List<Point2D> computeLine(Double dist, List<Point2D> pList, List<Point2D> ndpList) {
        dist = dist * 0.00001;
        List<Point2D> newList = new ArrayList<>();  // 新的折线顶点，在compute函数当中，赋值
        System.out.println("开始计算新顶点");
        int count = pList.size();
        for (int index = 0; index < count; index++) {
            int startIndex = index == 0 ? count - 1 : index - 1;
            int endIndex = index;
            Double sina = operator(ndpList.get(startIndex), ndpList.get(endIndex));
            Double length = dist / sina;
            Point2D vector = reduce(ndpList.get(endIndex), ndpList.get(startIndex));
            newList.add(plus(pList.get(index), ride(vector, length)));
        }
        return newList;
    }

    public static boolean areaContains(List<Point2D> pointList, double pointX, double pointY) {
        Path2D path = new Path2D.Double();
        path.moveTo(pointList.get(0).x, pointList.get(0).y);
        for (int i = 1; i < pointList.size(); ++i) {
            path.lineTo(pointList.get(i).x, pointList.get(i).y);
        }
        path.lineTo(pointList.get(0).x, pointList.get(0).y);
        path.closePath();
        return path.contains(pointX, pointY);
    }

    public static boolean areaContains(double radius, Point2D centerPoint, Point2D p2) {
//        double r = Math.sqrt((centerPoint.x - p2.x) * (centerPoint.x - p2.x) + (centerPoint.y - p2.y) * (centerPoint.y - p2.y));

        double r = getDistance(centerPoint.y,centerPoint.x,p2.y,p2.x);

        if (radius >= r) {
            return true;
        } else {
            return false;
        }
    }

    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }

    /**
     * 通过经纬度获取距离(单位：米)
     *
     * @param lat1 纬度1
     * @param lng1 经度1
     * @param lat2 纬度2
     * @param lng2 经度2
     * @return 距离
     */
    public static double getDistance(double lat1, double lng1, double lat2,
                                     double lng2) {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lng1) - rad(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
                Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000d) / 10000d;
        return s;
    }


    public static List<Point2D> extendArea(String pointStr, double distance) {
        JSONObject jsonObject = JSONObject.parseObject(pointStr);
        JSONArray xarray = jsonObject.getJSONArray("coordinates");
        StringBuffer sb = new StringBuffer();
        for (Object i : xarray) {
            JSONArray temp = (JSONArray) i;
            sb.append(temp.get(0) + "," + temp.get(1) + ";");
        }
        String result = sb.substring(0, sb.length() - 1);
        List<Point2D> pList = initPList(result);
        List<Point2D> dpList = initDPList(pList);
        List<Point2D> ndpList = initNDPList(dpList);
        return computeLine(distance, pList, ndpList);
    }
}
